using System;
using System.Collections;
using UnityEngine;

public class Player : Entity
{
    public static Player Instance;
    public static Action OnPlayerDead = delegate { }; //玩家死亡事件

    public UI uI { get; private set; }
    public PlayerSkillManager playerSkillManager { get; private set; }
    public Player_VFX player_VFX { get; private set; }
    public Player_Health playerHealth { get; private set; }
    public PlayerInput playerInput { get; private set; }
    public Player_Stats playerStats { get; private set; }
    public Entity_Combat entityCombat { get; private set; }
    public Inventory_Player playerInventory { get; private set; }
    public PlayerQuestManager questManager { get; private set; }

    [Header("-----Move Info-----")]
    public Vector2 mouseInput;
    public Vector2 moveInput;
    [SerializeField] private float moveSpeed; //移动速度
    [SerializeField] private float jumpForce; //跳跃力
    [SerializeField] private Vector2 wallJumpForce; //墙壁跳跃力
    
    [Range(0, 1)] public float inAirMoveMultiplier = .7f; //空中移动速度参数
    [Range(0, 1)] public float wallSlideSlowMutiplier = 0.4f;

    [Header("----- Attack Details-----")]
    public float comboWindow = 0.5f;
    [SerializeField] private Vector2[] attackMovements; //攻击移动向量
    [SerializeField] private Vector2 jumpAttackMovement;


    [Header("----- Dash Details-----")]
    public float dashDuration; //冲刺持续时间
    public float dashMoveSpeed; //冲刺速度
    public float dashDir; //冲刺方向

    [Header("----- Domain Details-----")]
    public float maxExpandDistance = 10f;
    public float riseSpeed = 50f;

    public Coroutine queueAttackCoroutine { get; private set; }

    #region AnimatorState

    public Player_IdleState idleState { get; private set; }
    public Player_MoveState moveState { get; private set; }
    public Player_JumpUpState jumpUpState { get; private set; }
    public Player_JumpFallState jumpFallState { get; private set; }
    public Player_DashState dashState { get; private set; }
    public Player_WallSlideState wallSildeState{ get; private set; }
    public Player_WallJumpState wallJumpState { get; private set; }
    public Player_BaseAttackState baseAttackState { get; private set; }
    public PlayerJumpAttackState jumpAttackState { get; private set; }
    public Player_DeadState deadState { get; private set; }
    public Player_CounterAttackState counterAttackState { get; private set; }
    public Player_SwordThrowState swordThrowState { get; private set; }
    public Player_DomainExpansionState domainExpansionState { get; private set; }
    #endregion

    #region GetData & DataScale
    private float scaleFactor = 1;
    public float GetMoveSpeed() => moveSpeed * scaleFactor;
    public float GetJumpForce() => jumpForce * scaleFactor;
    public Vector2 GetWallJumpForce() => wallJumpForce * scaleFactor;
    public Vector2 GetJumpAttackMovement() => jumpAttackMovement * scaleFactor;
    public Vector2[] GetAttackMovement()
    {
        Vector2[] scaleAttackMovement = new Vector2[attackMovements.Length];
        for (int i = 0; i < attackMovements.Length; i++)
            scaleAttackMovement[i] = attackMovements[i] * scaleFactor;
        return scaleAttackMovement;
    }
    #endregion

    #region 生命周期函数
    
    protected override void Awake()
    {
        base.Awake();
        Instance = this;
        playerInput = new PlayerInput();
        uI = FindObjectOfType<UI>();
        player_VFX = GetComponent<Player_VFX>();
        playerStats = GetComponent<Player_Stats>();
        playerHealth = GetComponent<Player_Health>();
        entityCombat = GetComponent<Entity_Combat>();
        playerSkillManager = GetComponent<PlayerSkillManager>();
        playerInventory = GetComponent<Inventory_Player>();
        questManager = GetComponent<PlayerQuestManager>();
        idleState = new(this, stateMachine, "Idle");
        moveState = new(this, stateMachine, "Move");
        jumpUpState = new(this, stateMachine, "Jump");
        jumpFallState = new(this, stateMachine, "Jump");
        dashState = new(this, stateMachine, "Dash");
        wallSildeState = new(this, stateMachine, "WallSilde");
        wallJumpState = new(this, stateMachine, "Jump");
        baseAttackState = new(this, stateMachine, "Attack");
        jumpAttackState = new(this, stateMachine, "JumpAttack");
        deadState = new(this, stateMachine, "Dead");
        counterAttackState = new(this, stateMachine, "CounterAttack");
        swordThrowState = new(this, stateMachine, "SwordThrow");
        domainExpansionState = new(this, stateMachine, "Jump");
    }
    private void OnEnable()
    {
        playerInput.Enable();

        playerInput.Player.Mouse.performed += context => mouseInput = context.ReadValue<Vector2>();
        playerInput.Player.Movement.performed += context => moveInput = context.ReadValue<Vector2>();
        playerInput.Player.Movement.canceled += context => moveInput = Vector2.zero;

        playerInput.Player.Skill_Shard.performed += context => playerSkillManager.skillShard.TryUseSkill();
        playerInput.Player.Skill_TimeEcho.performed += context => playerSkillManager.skillTimeEcho.TryUseSkill();

        playerInput.Player.QuickSlot_1.performed += context => playerInventory.TryUseQuickSlotItem(1);
        playerInput.Player.QuickSlot_2.performed += context => playerInventory.TryUseQuickSlotItem(2);

        playerInput.Player.Interact.performed += context => TryInteract();

        uI.SetUI(playerInput);
    }
    private void OnDisable()
    {
        playerInput.Disable();
    }
    
    protected override void Start()
    {
        base.Start();
        stateMachine.InitMachine(idleState);
    }
    protected override void Update()
    {
        base.Update();
        DashCheck();
        stateMachine?.StateUpdate();
    }
    #endregion

    //尝试交互
    private void TryInteract()
    {
        Transform closestTarget = null;
        float closest = float.MaxValue;
        Collider2D[] objectAround = Physics2D.OverlapCircleAll(transform.position, 1f);
        foreach (var target in objectAround)
        {
            IInteractable interactable = target.GetComponent<IInteractable>();

            if (interactable == null) continue;

            float distance = transform.position.x - target.transform.position.x;
            if (distance < closest)
            {
                closest = distance;
                closestTarget = target.transform;
            }
        }
        
        //当找到目标交互并且目标交互提示显示时，才能进行交互（判断交互目标是否是NPC，如果是NPC，才进行判断交互提示的面板显隐，
        //          若不是NPC， closestTarget.GetComponent<Object_NPC>()为空，
        //          closestTarget.GetComponent<Object_NPC>()?.IsEnableInteractToolTip() == false判断返回false）
        if (closestTarget == null || closestTarget.GetComponent<Object_NPC>()?.IsEnableInteractToolTip() == false)
            return;
        
        closestTarget.GetComponent<IInteractable>().Interact();
    }
    public void SetTeleportPosition(Vector2 targetPosition) => transform.position = targetPosition;
    public override void EntityDead()
    {
        base.EntityDead();
        //转换死亡状态
        stateMachine.ChangeState(deadState);
        //刚体不再受物理引擎影响，相当于暂时 "冻结" 了物理模拟
        //物体不会响应重力、碰撞等物理效果，但仍可以通过代码直接修改其位置和旋转
        //碰撞器仍然会检测碰撞，但不会产生物理响应
        rb.simulated = false;
        //禁用外设输入
        playerInput.Disable();
        //广播玩家死亡事件
        OnPlayerDead?.Invoke();
    }
    public void EnterAttackStateWithDelay()
    {
        if (queueAttackCoroutine != null)
        {
            StopCoroutine(queueAttackCoroutine);
        }
        queueAttackCoroutine = StartCoroutine(EnterAttackStateWithDelayCoroutine());
    }
    private IEnumerator EnterAttackStateWithDelayCoroutine()
    {
        yield return new WaitForEndOfFrame();
        stateMachine.ChangeState(baseAttackState);
    }
    protected override IEnumerator SlowDownEntityCo(float duration, float slowMultiplier)
    {
        scaleFactor = 1 - slowMultiplier;

        animator.speed = scaleFactor;

        yield return new WaitForSeconds(duration);
        StopSlowdownEntityCo();
    }
    public override void StopSlowdownEntityCo()
    {
        scaleFactor = 1f;
        animator.speed = scaleFactor;
        base.StopSlowdownEntityCo();

    }
    

    //冲刺检测
    public void DashCheck()
    {
        if (IsWall) return;
        dashDir = moveInput.x;
        //如果玩家没有水平输入
        if (dashDir == 0)
        {
            //冲刺方向为面朝方向
            dashDir = facingDir;
        }
    }
    
}
